package com.kh.statistics.video.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.kh.statistics.video.base.ClientEnum;
import com.kh.statistics.video.constant.AccountsConstant;
import com.kh.statistics.video.core.login.AccountsLogin;
import com.kh.statistics.video.core.pool.RunnableTask;
import com.kh.statistics.video.core.pool.TaskManager;
import com.kh.statistics.video.entity.Accounts;
import com.kh.statistics.video.entity.VideoAccountStatusVO;
import com.kh.statistics.video.entity.VideoAccountsHealth;
import com.kh.statistics.video.entity.VideoAccountsLogin;
import com.kh.statistics.video.entity.converter.VideoAccountStatusVOConverter;
import com.kh.statistics.video.exception.BizException;
import com.kh.statistics.video.exception.ResponseStatusEnum;
import com.kh.statistics.video.factory.AccountsFactory;
import com.kh.statistics.video.service.AccountLoginService;
import com.kh.statistics.video.service.VideoAccountsHealthService;
import com.kh.statistics.video.service.VideoAccountsService;
import com.kh.statistics.video.utils.WebDriverUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @BelongsProject: statistics
 * @BelongsPackage: com.kh.statistics.video.service.impl
 * @Author: Hong.Kong
 * @CreateTime: 2024-05-11  14:03
 * @Description: TODO
 * @Version: 1.0
 */
@Component
@Slf4j
public class VideoAccountsServiceImpl implements VideoAccountsService, InitializingBean {

    @Value("${statistics.selenium.driver}")
    private String driverUrl;

    private WebDriver driver = null;


    @Autowired
    private AccountLoginService accountLoginService;

    @Autowired
    private AccountsFactory accountsFactory;

    @Autowired
    private ListOperations<String, Object> redisTemplate;

    @Autowired
    private TaskManager taskManager;

    @Autowired
    private VideoAccountStatusVOConverter videoAccountStatusVOConverter;

    @Autowired
    private VideoAccountsHealthService videoAccountsHealthService;

    @Override
    public void add(Accounts accounts) {
        if (isAccountsExist(accounts)) {
            accounts.setId(RandomUtil.randomString(16));
            redisTemplate.leftPush(AccountsConstant.VIDEO_ACCOUNTS, JSON.toJSONString(accounts));
            return;
        }
        throw new BizException(ResponseStatusEnum.SYSTEM_ERROR.getCode(), "账户已经存在");
    }


    @Override
    public List<Accounts> search(Accounts accounts) {
        List<Object> list = redisTemplate.range(AccountsConstant.VIDEO_ACCOUNTS, 0, -1);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        if (null == accounts) {
            return list.stream().map(item -> JSON.parseObject(item.toString(), Accounts.class)).collect(Collectors.toList());
        }
        return list.stream().map(item -> JSON.parseObject(item.toString(), Accounts.class))
                .filter((item) -> {
                    if (null == accounts.getName() && null == accounts.getId()) {
                        return true;
                    }
                    if (null != accounts.getName() && item.getName().contains(accounts.getName())) {
                        return true;
                    }
                    if (null != accounts.getId() && item.getId().equals(accounts.getId())) {
                        return true;
                    }
                    return false;
                }).collect(Collectors.toList());
    }

    @Override
    public Boolean deleteById(Accounts accounts) {
        redisTemplate.remove(AccountsConstant.VIDEO_ACCOUNTS, 0, JSON.toJSONString(accounts));
        accountLoginService.deleteById(accounts.getId());
        return videoAccountsHealthService.deleteById(accounts.getId());
    }

    @Override
    public Boolean login(VideoAccountsLogin videoAccountsLogin) throws IOException {
        try {
            AccountsLogin accountsLogin = accountsFactory.getAccountsLogin(videoAccountsLogin.getPlatform());
            if (StringUtils.isBlank(videoAccountsLogin.getCookies())) {
                if (null == driver) {
                    try {
                        log.info("程序启动中,加载必要资源：{}", driverUrl);
                        driver = new RemoteWebDriver(new URL(driverUrl), DesiredCapabilities.chrome());
                    } catch (MalformedURLException e) {
                        driver = null;
                        throw new RuntimeException(e);
                    }
                }
                driver.manage().window().maximize();
                WebDriverUtils.setTimeOut(driver, 10, TimeUnit.SECONDS);
                accountsLogin.login(videoAccountsLogin, driver);
            }
            accountLoginService.saveLoginLog(videoAccountsLogin);
            new Thread(healthChecks("登录检测")).start();
            //处理登录记录
            return true;
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public Boolean update(Accounts accounts) {
        if (null == accounts) {
            return false;
        }
        if (isAccountsExist(accounts)) {
            List<Accounts> search = search(null);
            if (CollectionUtils.isEmpty(search)) {
                return false;
            }

            search.forEach((item) -> {
                if (item.getId().equals(accounts.getId())) {
                    redisTemplate.remove(AccountsConstant.VIDEO_ACCOUNTS, 0, JSON.toJSONString(item));
                    redisTemplate.leftPush(AccountsConstant.VIDEO_ACCOUNTS, JSON.toJSONString(accounts));
                }
            });
            return true;
        }
        throw new BizException(ResponseStatusEnum.SYSTEM_ERROR.getCode(), "账户已经存在");
    }

    @Override
    public List<VideoAccountStatusVO> searchAccountStatusList() {
        List<VideoAccountsHealth> videoAccountsHealths = videoAccountsHealthService.searchAll();
        List<Accounts> accountsList = search(null);

        if (CollectionUtils.isEmpty(videoAccountsHealths) || CollectionUtils.isEmpty(accountsList)) {
            return new ArrayList<>();
        }
        List<VideoAccountStatusVO> videoAccountStatusVOList = videoAccountStatusVOConverter.batchConvert(videoAccountsHealths);
        Map<String, Accounts> accountsMap = accountsList.stream().collect(Collectors.toMap(Accounts::getId, item -> item));

        videoAccountStatusVOList.forEach((item) -> {
            Accounts accounts = accountsMap.get(item.getId());
            if (null != accounts) {
                item.setName(accounts.getName());
            }
            item.setUpdateTime(DateUtil.format(new Date(item.getTimestamp()), "yyyy-MM-dd HH:mm:ss"));
        });
        return videoAccountStatusVOList.stream().sorted((o1, o2) -> {
            String id = o1.getId();
            String id1 = o2.getId();
            int aHashCode = id.hashCode();
            int bHashCode = id1.hashCode();
            return Integer.compare(aHashCode, bHashCode);

        }).collect(Collectors.toList());
    }

    private boolean isAccountsExist(Accounts accounts) {
        List<Object> list = redisTemplate.range(AccountsConstant.VIDEO_ACCOUNTS, 0, -1);
        if (CollectionUtils.isEmpty(list)) {
            return true;
        }
        return list.stream().map(item -> JSON.parseObject(item.toString(), Accounts.class))
                .filter((item) -> {
                    if (StringUtils.isNotBlank(accounts.getId())) {
                        return !item.getId().equals(accounts.getId());
                    }
                    return true;
                })
                .noneMatch(item -> item.getName().equals(accounts.getName()));
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        taskManager.addTask(healthChecks("定时任务检测"), 60, 600, TimeUnit.SECONDS);

        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            log.info("程序即将结束,关闭资源中");
            //程序结束时删除.lock文件
            if (driver != null) {
                driver.quit();
            }
        }));
    }

    private RunnableTask healthChecks(String flag) {
        return () -> {
            log.info("用户平台登录监控检测：【{}】", flag);
            List<VideoAccountsLogin> videoAccountsLogins = accountLoginService.searchAll();
            if (CollectionUtils.isEmpty(videoAccountsLogins)) {
                return;
            }
            for (VideoAccountsLogin videoAccountsLogin : videoAccountsLogins) {
                try {
                    AccountsLogin accountsLogin = accountsFactory.getAccountsLogin(videoAccountsLogin.getPlatform());
                    ClientEnum clientEnum = ClientEnum.getClientEnum(videoAccountsLogin.getClient());
                    VideoAccountsHealth videoAccountsHealth = null;
                    if (null == clientEnum || ClientEnum.CREATOR.equals(clientEnum)) {
                        videoAccountsHealth = accountsLogin.creatorHealthChecks(videoAccountsLogin);
                    }
                    if (ClientEnum.WEB.equals(clientEnum)){
                        videoAccountsHealth = accountsLogin.webHealthChecks(videoAccountsLogin);
                    }
                    if (null == videoAccountsHealth) {
                        return;
                    }
                    videoAccountsHealthService.add(videoAccountsHealth);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
    }
}
